package com.eryos.android.cigarettecounter.io;

/**
 * Project :  CigaretteCounter
 * Author :   Olivier Combe 
 * URL :      http://eryos.fr/CigaretteCounter/
 *
 * Copyright (C) 2011 - Olivier Combe 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Locale;
import java.util.TimeZone;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import com.eryos.android.cigarettecounter.R;

public class LogReporter  {
    
	private final static String LOG_TAG 	= "LogReporter";
	private static final String LINE_RETURN = "\n";
	private static final String LINE_SEPARATOR = "\n-------------------------------------\n";

	private String logFileName = "log-cigarettecounter.txt";

	private ArrayList<String> emailList;
	private ArrayList<String> emailList_cc;
	private ArrayList<String> emailList_bcc;
	private ArrayList<String> logFilterList;
	private String subject	= "Log Trace";
	private String message	= "Please find log trace file in attachment";
	private String type		= "message/rfc822";//text/plain";
	private Uri attachedFile;
	private int maxLineNumbers = 1000;
	private Context context;
	private String debugInfo	= "";
	
	
	/**
	 * Create a new log report
	 */
	public LogReporter(Context ctx){
		Log.d(LOG_TAG, LOG_TAG);
    	
		context = ctx;
		emailList 		= new ArrayList<String>();
		emailList_cc 	= new ArrayList<String>();
		emailList_bcc 	= new ArrayList<String>();
		logFilterList 	= new ArrayList<String>();		
		
		Calendar c = Calendar.getInstance();
		String timestamp = c.get(Calendar.YEAR)+""+
		c.get(Calendar.MONTH)+""+
		c.get(Calendar.DAY_OF_MONTH)+""+
		c.get(Calendar.HOUR_OF_DAY)+""+
		c.get(Calendar.MINUTE)+""+
		c.get(Calendar.SECOND);
		
		logFileName = "log_cigarettecounter_"+timestamp+".txt";
	}

	/**
	 * Method used to retrieve log and write trace on SD Card
	 */
	public void retrieveLogs(){
		Log.d(LOG_TAG, "retrieveLogs()");
    	
		ArrayList<String> logs = generateLogTrace();

		/* Export data to external file */
		DataExporter export = new DataExporter(logFileName);

		try { 
			if ( export.openStream() ) {

				Log.d(LOG_TAG, "write logs to SD Card File");
		    	for ( String line : logs )
					export.writeDataToExternalFile(line+LINE_RETURN);

				export.closeStream();
			}
		}catch (IOException e){
			e.printStackTrace();
		}

		/* Create the Uri reference */
		attachedFile  = Uri.parse("file://"+ export.getFullPathName());
		Log.d(LOG_TAG, "Uri : "+"file://"+ export.getFullPathName());
	}

	/**
	 * Method used to retrieve logs from "logcat" command
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<String> generateLogTrace(){
		Log.d(LOG_TAG, "generateLogTrace()");
    	
		ArrayList<String> logs = new ArrayList<String>();

		try {
			/* Run logcat command */
			ArrayList<String> commandLine = new ArrayList<String>();
			commandLine.add("logcat");
			commandLine.add("-d");
			commandLine.add("-v");
			commandLine.add("time");
			
	        if (logFilterList != null){
	        	Log.d(LOG_TAG, "add FilterSpecs");
	            for (String filterSpec : logFilterList){
	                commandLine.add(filterSpec);
	            }
	        }

	        String cmd = "";
            for ( String arg : commandLine.toArray(new String[0])) 
            	cmd = cmd + " "+arg;
            
			Log.d(LOG_TAG, "run logcat cmd : "+cmd);
	    	Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0]));
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			
			/* Browse complete log trace */
			Log.d(LOG_TAG, "Browse complete logs");
	    	String line;
			while ((line = bufferedReader.readLine()) != null){ 
			    
				/* Apply defined filters to logs */
				if (logFilterList != null && logFilterList.size() > 0 ){
					for ( String tag : logFilterList ){
						if ( line.toLowerCase().contains(tag.toLowerCase()) ){			
							logs.add(line);
							break;
						}
					}					
				}else {
					logs.add(line);
				}
			}
			Log.d(LOG_TAG, "Logs retrieve : "+logs.size());
		} catch (IOException e) {
			e.printStackTrace();
		}

		/* Reduce the number of lines if needed */
		Log.d(LOG_TAG, "Resize logs if needed");
    	if ( logs.size() > maxLineNumbers ) {
			int maxAuthorized = logs.size() - maxLineNumbers;
			Collection<String> listToRemove = ((ArrayList<String>) logs.clone()).subList(0, maxAuthorized); // use clone() to avoid ConcurrentModificationException
			logs.removeAll(listToRemove);
		}

		/* Return the final log list */
		return logs;
	}

	/**
	 * Method used to retrieve additional info like location, timezone, SDK version, etc.
	 */
	private void retrieveAdditionalInformation(){	
		Log.d(LOG_TAG, "retrieveAdditionalInformation()");
    	
		String appVersion 		= context.getString(R.string.version);
		String sdkVersion 		= Build.VERSION.SDK;
		String defaultCountry 	= Locale.getDefault().getDisplayCountry();
		String defaultLanguage 	= Locale.getDefault().getDisplayLanguage();
		String defaultTimezone 	= TimeZone.getDefault().getDisplayName();
	    String screenResolution = Build.DISPLAY;

		String infos = "";
		infos = infos + "App Version      : " 	+ appVersion 		+ LINE_RETURN;
		infos = infos + "SDK Version      : " 	+ sdkVersion 		+ LINE_RETURN;
		infos = infos + "Default Country  : " 	+ defaultCountry 	+ LINE_RETURN;
		infos = infos + "Default Language : " 	+ defaultLanguage 	+ LINE_RETURN;
		infos = infos + "Default TimeZone : " 	+ defaultTimezone 	+ LINE_RETURN;
		infos = infos + "Display          : " 	+ screenResolution 	+ LINE_RETURN;

		if ( message != null )
			message = message + 
				LINE_SEPARATOR + "Debug Information : " + LINE_RETURN + debugInfo + 
				LINE_SEPARATOR + "Additional Information : " + LINE_RETURN + infos;
	}

	/**
	 * Method used to raise an Intent for sending mail with pre-defined arguments
	 */
	public void sendLogs(){
		Log.d(LOG_TAG, "sendLogs()");
		
		/* Check if file is available on SD Card */
		if (true){
			
			/* Add extra info to Message Body */
			retrieveAdditionalInformation();
			
			/* Define the ACTION_SEND Intent */
			Intent sendMailIntent = new Intent(Intent.ACTION_SEND);
			sendMailIntent.setType(type);
			sendMailIntent.putExtra(Intent.EXTRA_EMAIL, 	emailList.toArray(new String[0]));
			sendMailIntent.putExtra(Intent.EXTRA_CC, 		emailList_cc.toArray(new String[0]));
			sendMailIntent.putExtra(Intent.EXTRA_BCC, 		emailList_bcc.toArray(new String[0]));
			sendMailIntent.putExtra(Intent.EXTRA_SUBJECT, 	subject);
			sendMailIntent.putExtra(Intent.EXTRA_TEXT, 		message);
			sendMailIntent.putExtra(Intent.EXTRA_STREAM, 	attachedFile);

			/* Raise the new Intent */
			Log.d(LOG_TAG, "startActivity(mailIntent)");
			context.startActivity(Intent.createChooser(sendMailIntent, "Choose an appli to send the mail"));
		}
	}

	/* ************** Getters & Setters ************** */

	public void addRecipient(String mail){
		emailList.add(mail);
	}

	public void addCopyRecipient(String mail){
		emailList_cc.add(mail);
	}

	public void addHiddenRecipient(String mail){
		emailList_bcc.add(mail);
	}

	public void setSubject(String _subject){
		subject = _subject;
	}

	public void setMessage(String _message){
		message = _message;
	}

	public void addFilter(String tag){
		logFilterList.add(tag);
	}

	public void setMaxLineNumbers(int max){
		maxLineNumbers = max;
	}

	public String getDebugInfo() {
		return debugInfo;
	}

	public void setDebugInfo(String debugInfo) {
		this.debugInfo = debugInfo;
	}
	

}